using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
using System.Net.Mail;
using System.Xml;
using System.IO;
using System.CodeDom.Compiler;

namespace Lds.Ward.PhotoDirectory.Logic
{
	public class Family
	{
		public Family() { }
		public Family(string surname, PhoneNumber phone)
		{
			Surname = surname;
			Telephone = phone;
		}

		private string surname;

		public string Surname
		{
			get { return surname; }
			set { surname = value; }
		}

		private PhoneNumber telephone;

		public PhoneNumber Telephone
		{
			get { return telephone; }
			set { telephone = value; }
		}

		private MailAddress email;

		public MailAddress Email
		{
			get { return email; }
			set { email = value; }
		}

		private PostalAddress mailingAddress = new PostalAddress();

		public PostalAddress MailingAddress
		{
			get { return mailingAddress; }
			set { mailingAddress = value; }
		}

		public string GetPhotoPath(Uri path)
		{
			if (path == null) throw new ArgumentNullException("path");
			string[] possibleFilenames = new string[] { 
				Surname + ", " + FirstNameOfHead,
				Surname + "_" + FirstNameOfHead,
				Surname + ", " + FirstNameOfHead.Substring(0,1),
				Surname + "_" + FirstNameOfHead.Substring(0,1),
				Surname,
				Surname + "s",
				};
			foreach (string possibleFilename in possibleFilenames)
			{
				Uri photoPath = new Uri(path, possibleFilename + ".jpg");
				if (File.Exists(photoPath.LocalPath))
					return photoPath.LocalPath;
			}
			return null;
		}

		public bool HasPhoto(Uri path)
		{
			return GetPhotoPath(path) != null;
		}

		private string FirstNameOfHead
		{
			get
			{
				if (FamilyMembers.Count == 0) return null;
				string givenName = FamilyMembers[0].GivenNames;
				if (givenName.IndexOf(' ') >= 0) givenName = givenName.Substring(0, givenName.IndexOf(' '));
				return givenName;
			}
		}

		private List<FamilyMember> familyMembers = new List<FamilyMember>();

		public List<FamilyMember> FamilyMembers
		{
			get { return familyMembers; }
		}

		public override string ToString()
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder();
			sb.AppendFormat("{0} {1} {2}{3}{4}{3}", Surname, Telephone,
				Email, Environment.NewLine, MailingAddress);
			foreach (FamilyMember member in FamilyMembers)
				sb.Append(member);
			return sb.ToString();
		}

		public void ToXml(XmlWriter writer, Uri photosDirectory, TempFileCollection thumbnailFiles, MediaQuality quality)
		{
			if (writer == null) throw new ArgumentNullException("writer");
			writer.WriteStartElement("family");
			WriteAttribute(writer, "surname", Surname);
			WriteAttribute(writer, "email", Email);
			WriteAttribute(writer, "phone", Telephone);
			WriteAttribute(writer, "address", MailingAddress.StreetAddress);
			WriteAttribute(writer, "apartment", MailingAddress.ApartmentNumber);
			WriteAttribute(writer, "city", MailingAddress.City);
			WriteAttribute(writer, "state", MailingAddress.State);
			WriteAttribute(writer, "zip", MailingAddress.PostalCode);
			WriteAttribute(writer, "photo", PreparePhoto(GetPhotoPath(photosDirectory), thumbnailFiles, quality));

			foreach (FamilyMember fm in FamilyMembers)
				fm.ToXml(writer);

			writer.WriteEndElement();
		}

		public virtual string PreparePhoto(string highQualityPhotoPath, TempFileCollection thumbnailFiles, MediaQuality quality)
		{
			const long jpegQuality = 80L;
			if (highQualityPhotoPath == null) return null;
			using (Image original = new Bitmap(highQualityPhotoPath))
			{
				Size resolution;
				switch (quality)
				{
					case MediaQuality.Maximum:
						return highQualityPhotoPath;
					case MediaQuality.Print:
						resolution = new Size(800, 800 * original.Size.Height / original.Size.Width);
						break;
					case MediaQuality.Screen:
						resolution = new Size(500, 500 * original.Size.Height / original.Size.Width);
						break;
					case MediaQuality.WardWebSite:
						resolution = new Size(180, 180 * original.Size.Height / original.Size.Width);
						break;
					default:
						throw new ArgumentOutOfRangeException("quality", quality, "Unexpected value.");
				}
				string thumbnailFileName = Path.ChangeExtension(Path.GetRandomFileName(), "jpg");
				string thumbnailDirectory = thumbnailFiles.BasePath.Substring(0, thumbnailFiles.BasePath.LastIndexOf(Path.DirectorySeparatorChar));
				string thumbnailPath = Path.Combine(thumbnailDirectory, thumbnailFileName);
				using (Image thumbnail = new Bitmap(original, resolution))
				{
					Graphics g = Graphics.FromImage(thumbnail);
					g.InterpolationMode = InterpolationMode.HighQualityBicubic;
					g.CompositingQuality = CompositingQuality.HighQuality;
					g.SmoothingMode = SmoothingMode.HighQuality;
					g.DrawImage(original, new Rectangle(0, 0, thumbnail.Size.Width, thumbnail.Size.Height));
					thumbnailFiles.AddFile(thumbnailPath, false);

					// Prepare for a controlled-quality JPEG export
					ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
					Encoder jpegEncoder = Encoder.Quality;
					EncoderParameters jpegEncoderParameters = new EncoderParameters(1);
					EncoderParameter jpegEncoderQuality = new EncoderParameter(jpegEncoder, jpegQuality);
					jpegEncoderParameters.Param[0] = jpegEncoderQuality;

					thumbnail.Save(thumbnailPath, jpegCodec, jpegEncoderParameters);
				}
				return thumbnailPath;
			}
		}

		private static ImageCodecInfo GetEncoderInfo(String mimeType)
		{
			int j;
			ImageCodecInfo[] encoders;
			encoders = ImageCodecInfo.GetImageEncoders();
			for (j = 0; j < encoders.Length; ++j)
			{
				if (encoders[j].MimeType == mimeType)
					return encoders[j];
			}
			return null;
		}

		internal static void WriteAttribute(XmlWriter write, string name, object value)
		{
			if (value != null && value.ToString().Length > 0)
				write.WriteAttributeString(name, value.ToString());
		}
	}
}
